package StudyCode.summary.utf;

import java.io.OutputStream;

/**
 * 版权所有 科技与人文(www.tah1986.com)
 */
public class WritesAPortionOfAStringInUTF8EncodingToADataStream {
	private static final int StreamedStringBufferLength = 4096;


	public static int WriteUtf8(String str, int offset, int length,
	                            OutputStream stream, boolean replace)
			throws java.io.IOException {
		return WriteUtf8(str, offset, length, stream, replace, false);
	}


	public static int WriteUtf8(String str, int offset, int length,
	                            OutputStream stream, boolean replace, boolean lenientLineBreaks)
			throws java.io.IOException {
		if (stream == null) {
			throw new NullPointerException("stream");
		}
		if (str == null) {
			throw new NullPointerException("str");
		}
		if (offset < 0) {
			throw new IllegalArgumentException("offset (" + offset
					+ ") is less than " + "0");
		}
		if (offset > str.length()) {
			throw new IllegalArgumentException("offset (" + offset
					+ ") is more than " + str.length());
		}
		if (length < 0) {
			throw new IllegalArgumentException("length (" + length
					+ ") is less than " + "0");
		}
		if (length > str.length()) {
			throw new IllegalArgumentException("length (" + length
					+ ") is more than " + str.length());
		}
		if (str.length() - offset < length) {
			throw new IllegalArgumentException(
					"str.length() minus offset (" + (str.length() - offset)
							+ ") is less than " + length);
		}
		byte[] bytes;
		int retval = 0;
		bytes = new byte[StreamedStringBufferLength];
		int byteIndex = 0;
		int endIndex = offset + length;
		for (int index = offset; index < endIndex; ++index) {
			int c = str.charAt(index);
			if (c <= 0x7f) {
				if (lenientLineBreaks) {
					if (c == 0x0d
							&& (index + 1 >= endIndex || str
							.charAt(index + 1) != 0x0a)) {
						if (byteIndex + 2 > StreamedStringBufferLength) {
							stream.write(bytes, 0, byteIndex);
							byteIndex = 0;
						}
						bytes[byteIndex++] = 0x0d;
						bytes[byteIndex++] = 0x0a;
						continue;
					}
					if (c == 0x0a) {
						if (byteIndex + 2 > StreamedStringBufferLength) {
							stream.write(bytes, 0, byteIndex);
							byteIndex = 0;
						}
						bytes[byteIndex++] = 0x0d;
						bytes[byteIndex++] = 0x0a;
						continue;
					}
				}
				if (byteIndex >= StreamedStringBufferLength) {
					stream.write(bytes, 0, byteIndex);
					byteIndex = 0;
				}
				bytes[byteIndex++] = (byte) c;
			} else if (c <= 0x7ff) {
				if (byteIndex + 2 > StreamedStringBufferLength) {
					stream.write(bytes, 0, byteIndex);
					byteIndex = 0;
				}
				bytes[byteIndex++] = (byte) (0xc0 | ((c >> 6) & 0x1f));
				bytes[byteIndex++] = (byte) (0x80 | (c & 0x3f));
			} else {
				if ((c & 0xfc00) == 0xd800 && index + 1 < endIndex
						&& str.charAt(index + 1) >= 0xdc00
						&& str.charAt(index + 1) <= 0xdfff) {
					c = 0x10000 + ((c - 0xd800) << 10)
							+ (str.charAt(index + 1) - 0xdc00);
					++index;
				} else if ((c & 0xf800) == 0xd800) {
					if (!replace) {
						retval = -1;
						break;
					}
					c = 0xfffd;
				}
				if (c <= 0xffff) {
					if (byteIndex + 3 > StreamedStringBufferLength) {
						stream.write(bytes, 0, byteIndex);
						byteIndex = 0;
					}
					bytes[byteIndex++] = (byte) (0xe0 | ((c >> 12) & 0x0f));
					bytes[byteIndex++] = (byte) (0x80 | ((c >> 6) & 0x3f));
					bytes[byteIndex++] = (byte) (0x80 | (c & 0x3f));
				} else {
					if (byteIndex + 4 > StreamedStringBufferLength) {
						stream.write(bytes, 0, byteIndex);
						byteIndex = 0;
					}
					bytes[byteIndex++] = (byte) (0xf0 | ((c >> 18) & 0x07));
					bytes[byteIndex++] = (byte) (0x80 | ((c >> 12) & 0x3f));
					bytes[byteIndex++] = (byte) (0x80 | ((c >> 6) & 0x3f));
					bytes[byteIndex++] = (byte) (0x80 | (c & 0x3f));
				}
			}
		}
		stream.write(bytes, 0, byteIndex);
		return retval;
	}


	public static int WriteUtf8(String str, OutputStream stream,
	                            boolean replace) throws java.io.IOException {
		if (str == null) {
			throw new NullPointerException("str");
		}
		return WriteUtf8(str, 0, str.length(), stream, replace);
	}
}
